#include "user_server.h"

#include <cctype>
#include <functional>

#include "base.pb.h"
#include "file.pb.h"
#include "file_io.h"
#include "log.h"
#include "user.hxx"
#include "uuid.h"

namespace chat {
// UserServerImpl

bool UserServerImpl::checkNickname(const std::string& nickname) {
    return !(nickname.size() > 21);
}

bool UserServerImpl::checkPassword(const std::string& password) {
    for (auto& ch : password) {
        if (!(isdigit(ch) || isalpha(ch))) {
            return false;
        }
    }

    return true;
}

bool UserServerImpl::checkPhone(const std::string& phone) {
    // 必须以1开始，第二位3~9之间，后边9个数字字符

    if (phone.size() != 11) {
        return false;
    }
    if (phone[0] != '1') {
        return false;
    }
    if (phone[1] < '3' || phone[1] > '9') {
        return false;
    }
    for (int i = 2; i < 11; ++i) {
        if (!isdigit(phone[i])) {
            return false;
        }
    }

    return true;
}

bool UserServerImpl::appendESData(const User user) {
    return es_user_->appendData(
        user.user_id(), !user.phone() ? "" : *(user.phone()), user.nickname(),
        !user.description() ? "" : *user.description(),
        !user.avatar_id() ? "" : *user.avatar_id());
}

std::string UserServerImpl::getCode() {
    std::string code;

    // 1. 创建一个机器随机数对象
    std::random_device rd;
    // 2. 将机器随机数作为种子，生成伪随机对象
    std::mt19937 generator(rd());
    // 3. 限制随机数范围 [0, 9]
    std::uniform_int_distribution<int> distribution(0, 9);

    for (int i = 0; i < 4; ++i) {
        code += std::to_string(distribution(generator));
    }

    return code;
}

void UserServerImpl::UserRegister(::google::protobuf::RpcController* controller,
                                  const ::chat::UserRegisterReq* request,
                                  ::chat::UserRegisterRsp* response,
                                  ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);
    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";

    LOG_DEBUG("收到用户注册请求: {}", request_id);

    do {
        // 1. 从请求中取出昵称和密码
        std::string nickname = request->nickname();
        std::string password = request->password();

        // 2. 检查昵称是否合法
        if (!checkNickname(nickname)) {
            LOG_ERROR("{}: {} 昵称太长", request_id, nickname);

            is_success = false;
            err_msg = "昵称太长";

            break;
        }

        // 3. 检查密码是否合法
        if (!checkPassword(password)) {
            LOG_ERROR("{}: {} 密码中存在非法字符", request_id, password);

            is_success = false;
            err_msg = "密码中存在非法字符";

            break;
        }

        // 4. 根据昵称在数据库进行判断是否昵称已存在
        if (odb_user_->select_by_nickname(nickname)) {
            LOG_ERROR("{}: {} 用户已经被注册", request_id, nickname);

            is_success = false;
            err_msg = "用户已经被注册";

            break;
        }

        // 5. 向数据库新增数据
        UserPtr user = std::make_shared<User>(Uuid::uuid(), nickname, password);
        if (!odb_user_->insert(user)) {
            LOG_ERROR("{}: {} 用户添加到数据库失败", request_id, nickname);

            is_success = false;
            err_msg = "用户添加到数据库失败";

            break;
        }

        // 6. 向ES服务器中新增用户信息
        if (!appendESData({Uuid::uuid(), nickname, password})) {
            LOG_ERROR("{}: {} 用户添加到ES数据库失败", request_id, nickname);

            is_success = false;
            err_msg = "用户添加到ES数据库失败";

            break;
        }

    } while (0);

    // 7. 组织响应，进行成功与否的响应即可。
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理用户注册请求: {}", request_id);
}

void UserServerImpl::UserLogin(::google::protobuf::RpcController* controller,
                               const ::chat::UserLoginReq* request,
                               ::chat::UserLoginRsp* response,
                               ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";
    std::string session_id;

    LOG_DEBUG("收到用户登录请求: {}", request_id);

    do {
        // 1. 从请求中取出昵称和密码
        std::string nickname = request->nickname();
        std::string password = request->password();

        // 2. 通过昵称获取用户信息，进行密码是否一致的判断
        std::shared_ptr<User> user = odb_user_->select_by_nickname(nickname);
        if (user == nullptr) {
            LOG_ERROR("{}: {} 用户不存在", request_id, nickname);

            is_success = false;
            err_msg = "用户不存在";

            break;
        }

        if (!user->password() || *user->password() != password) {
            LOG_ERROR("{}: {} 密码错误", request_id, nickname);

            is_success = false;
            err_msg = "密码错误";

            break;
        }

        // 3. 根据redis中的登录标记信息是否存在判断用户是否已经登录。
        if (redis_status_->exists(user->user_id())) {
            LOG_ERROR("{}: {} 用户已经在别处登录", request_id, nickname);

            is_success = false;
            err_msg = "用户已经在别处登录";

            break;
        }

        // 4. 构造会话ID，生成会话键值对，向redis中添加会话信息以及登录标记信息
        session_id = Uuid::uuid();
        if (!redis_session_->append(session_id, user->user_id())) {
            LOG_ERROR("{}: {} 添加Redis会话失败", request_id, nickname);

            is_success = false;
            err_msg = "添加Redis会话失败";

            break;
        }

    } while (0);

    // 5. 组织响应，返回生成的会话ID
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);
    response->set_login_session_id(session_id);

    LOG_DEBUG("成功处理用户登录请求: {}", request_id);
}

void UserServerImpl::GetPhoneVerifyCode(
    ::google::protobuf::RpcController* controller,
    const ::chat::PhoneVerifyCodeReq* request,
    ::chat::PhoneVerifyCodeRsp* response, ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";
    std::string code_id;

    LOG_DEBUG("收到获取手机验证码请求: {}", request_id);

    do {
        // 1. 从请求中取出手机号码
        std::string phone = request->phone_number();

        // 2.  验证手机号码格式是否正确
        if (!checkPhone(phone)) {
            LOG_ERROR("{}: {} 手机号格式错误", request_id, phone);

            is_success = false;
            err_msg = "手机号格式错误";

            break;
        }

        // 3. 生成4位随机验证码
        std::string code = getCode();

        // 4. 基于短信平台SDK发送验证码
        if (!sms_client_->send(code, phone)) {
            LOG_ERROR("{}: {}->{} 验证发发送失败", request_id, code, phone);

            is_success = false;
            err_msg = "验证发发送失败";

            break;
        }

        // 5. 构造验证码ID，添加到redis验证码映射键值索引中
        code_id = Uuid::uuid();
        if (!redis_codes_->append(code_id, code,
                                  std::chrono::milliseconds(60000))) {
            LOG_ERROR("{}: {} 添加验证码Redis管理失败");

            is_success = false;
            err_msg = "添加验证码Redis管理失败";

            break;
        }

    } while (0);

    // 6. 组织响应，返回生成的验证码ID
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);
    response->set_verify_code_id(code_id);

    LOG_DEBUG("成功处理获取手机验证码请求: {}", request_id);
}

void UserServerImpl::PhoneRegister(
    ::google::protobuf::RpcController* controller,
    const ::chat::PhoneRegisterReq* request, ::chat::PhoneRegisterRsp* response,
    ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";
    std::string code_id;

    LOG_DEBUG("收到手机号注册请求: {}", request_id);

    do {
        // 1. 从请求中取出手机号码和验证码
        std::string phone = request->phone_number();
        std::string code = request->verify_code();
        std::string code_id = request->verify_code_id();

        // 2. 检查注册手机号码是否合法
        if (!checkPhone(phone)) {
            LOG_ERROR("{}: {} 手机号格式错误", request_id, phone);

            is_success = false;
            err_msg = "手机号格式错误";

            break;
        }

        // 3. 通过数据库查询判断手机号是否已经注册过
        if (odb_user_->select_by_phone(phone)) {
            LOG_ERROR("{}: {} 手机号已经被注册", phone);

            is_success = false;
            err_msg = "手机号已经被注册";

            break;
        }

        // 4. 从redis数据库中进行验证码ID-验证码一致性匹配
        auto res = redis_codes_->code(code_id);
        if (res != code) {
            LOG_ERROR("{}: {} 验证码错误", code);

            is_success = false;
            err_msg = "验证码错误";

            break;
        }
        redis_codes_->remove(code_id);  // 使用完验证码后，就要从redis中删除

        // 5. 向数据库新增用户信息
        UserPtr user = std::make_shared<User>(Uuid::uuid(), phone);
        if (!odb_user_->insert(user)) {
            LOG_ERROR("{}: {} 用户添加到数据库失败", request_id, phone);

            is_success = false;
            err_msg = "用户添加到数据库失败";

            break;
        }

        // 6. 向ES服务器中新增用户信息
        if (!appendESData({Uuid::uuid(), phone})) {
            LOG_ERROR("{}: {} 用户添加到ES数据库失败", request_id, phone);

            is_success = false;
            err_msg = "用户添加到ES数据库失败";

            break;
        }

    } while (0);

    // 7. 组织响应，返回注册成功与否
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理手机号注册请求: {}", request_id);
}

void UserServerImpl::PhoneLogin(::google::protobuf::RpcController* controller,
                                const ::chat::PhoneLoginReq* request,
                                ::chat::PhoneLoginRsp* response,
                                ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";
    std::string session_id;

    LOG_DEBUG("收到手机号登录请求: {}", request_id);

    do {
        // 1. 从请求中取出手机号码和验证码ID，以及验证码。
        std::string phone = request->phone_number();
        std::string code = request->verify_code();
        std::string code_id = request->verify_code_id();

        // 2. 检查注册手机号码是否合法
        if (!checkPhone(phone)) {
            LOG_ERROR("{}: {} 手机号格式错误", request_id, phone);

            is_success = false;
            err_msg = "手机号格式错误";

            break;
        }

        // 3. 根据手机号从数据数据进行用户信息查询，判断用用户是否存在
        UserPtr user = odb_user_->select_by_phone(phone);
        if (user == nullptr) {
            LOG_ERROR("{}: {} 手机号还未注册", phone);

            is_success = false;
            err_msg = "手机号还未注册";

            break;
        }

        // 4. 从redis数据库中进行验证码ID-验证码一致性匹配
        auto res = redis_codes_->code(code_id);
        if (res != code) {
            LOG_ERROR("{}: {} 验证码错误", code);

            is_success = false;
            err_msg = "验证码错误";

            break;
        }
        redis_codes_->remove(code_id);  // 使用完验证码后，就要从redis中删除

        // 5. 根据redis中的登录标记信息是否存在判断用户是否已经登录。
        if (redis_status_->exists(user->user_id())) {
            LOG_ERROR("{}: {} 用户已经在别处登录", request_id, phone);

            is_success = false;
            err_msg = "用户已经在别处登录";

            break;
        }

        // 6. 构造会话ID，生成会话键值对，向redis中添加会话信息以及登录标记信息
        session_id = Uuid::uuid();
        if (!redis_session_->append(session_id, user->user_id())) {
            LOG_ERROR("{}: {} 添加Redis会话失败", request_id, phone);

            is_success = false;
            err_msg = "添加Redis会话失败";

            break;
        }

    } while (0);

    // 7. 组织响应，返回生成的会话ID
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);
    response->set_login_session_id(session_id);

    LOG_DEBUG("成功处理手机号登录请求: {}", request_id);
}

void UserServerImpl::GetUserInfo(::google::protobuf::RpcController* controller,
                                 const ::chat::GetUserInfoReq* request,
                                 ::chat::GetUserInfoRsp* response,
                                 ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";
    UserInfo* info = response->mutable_user_info();

    LOG_DEBUG("收到获取用户信息请求: {}", request_id);

    // 1. 从请求中取出用户ID
    std::string user_id = request->user_id();

    do {
        // 2. 通过用户ID，从数据库中查询用户信息
        UserPtr user = odb_user_->select_by_user_id(user_id);
        if (user == nullptr) {
            LOG_ERROR("{}: {}用户不存在", request_id, user_id);

            is_success = false;
            err_msg = "用户不存在";

            break;
        }
        info->set_user_id(user_id);
        info->set_nickname(user->nickname());
        if (user->description()) {
            info->set_description(*user->description());
        }
        if (user->phone()) {
            info->set_phone(*user->phone());
        }

        // 3. 根据用户信息中的头像ID，从文件服务器获取头像文件数据
        if (user->avatar_id()) {
            chat::ServiceChannel::ChannelPtr channel =
                service_manager_->choose(file_service_name_);
            if (nullptr == channel) {
                LOG_ERROR("{}: 未找到能够提供服务 {} 的节点", request_id,
                          file_service_name_);

                is_success = false;
                err_msg = "未找到能够提供服务的节点";

                break;
            }

            // 先发起Rpc调用，进行文件下载
            chat::FileService_Stub stub(channel.get());
            chat::GetSingleFileReq req;
            chat::GetSingleFileRsp rsp;
            req.set_request_id(Uuid::uuid());
            req.set_file_id(*user->avatar_id());

            brpc::Controller cntl;
            stub.GetSingleFile(&cntl, &req, &rsp, nullptr);
            if (cntl.Failed()) {
                LOG_ERROR("{}: {} 文件下载RPC调用失败", request_id,
                          *user->avatar_id());

                is_success = false;
                err_msg = "文件下载RPC调用失败";

                break;
            }
            if (!rsp.success()) {
                LOG_ERROR("{}: {} 文件下载响应错误", request_id,
                          *user->avatar_id());

                is_success = false;
                err_msg = "文件下载响应错误";

                break;
            }

            // 将文件数据，存储到info中
            if (req.file_id() != rsp.file_data().file_id()) {
                LOG_ERROR("{}: {}-{}下载文件请求id与响应文件id不一致",
                          req.file_id(), rsp.file_data().file_id());

                is_success = false;
                err_msg = "下载文件请求id与响应文件id不一致";

                break;
            }
            info->set_avatar(rsp.file_data().file_content());
        }
    } while (0);

    // 4. 组织响应，返回用户信息
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理获取用户信息请求: {}", request_id);
}

void UserServerImpl::GetMultiUserInfo(
    ::google::protobuf::RpcController* controller,
    const ::chat::GetMultiUserInfoReq* request,
    ::chat::GetMultiUserInfoRsp* response, ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";
    auto info_map = response->mutable_users_info();

    LOG_DEBUG("收到批量获取用户数据请求: {}", request_id);

    // 1. 从请求中取出用户ID
    std::vector<std::string> user_ids;
    for (int i = 0; i < request->users_id_size(); ++i) {
        user_ids.push_back(request->users_id(i));
    }

    do {
        // 2. 通过用户ID，从数据库中查询用户信息
        std::vector<User> users = odb_user_->select_multi_by_ids(user_ids);
        if (users.size() != request->users_id_size()) {
            LOG_ERROR("{}: {}-{} 批量用户查询数量不匹配不存在", request_id,
                      users.size(), request->users_id_size());

            is_success = false;
            err_msg = "批量用户查询数量不匹配不存在";

            break;
        }

        // 3. 根据用户信息中的头像ID，从文件服务器获取头像文件数据
        chat::ServiceChannel::ChannelPtr channel =
            service_manager_->choose(file_service_name_);
        if (nullptr == channel) {
            LOG_ERROR("{}: 未找到能够提供服务 {} 的节点", request_id,
                      file_service_name_);

            is_success = false;
            err_msg = "未找到能够提供服务的节点";

            break;
        }

        // 4. 先发起Rpc调用，进行批量文件下载
        chat::FileService_Stub stub(channel.get());
        chat::GetMultiFileReq req;
        chat::GetMultiFileRsp rsp;
        req.set_request_id(Uuid::uuid());
        for (auto& user : users) {
            if (user.avatar_id()) {
                req.add_file_id_list((*user.avatar_id()).c_str());
            }
        }

        brpc::Controller cntl;
        stub.GetMultiFile(&cntl, &req, &rsp, nullptr);
        if (cntl.Failed()) {
            LOG_ERROR("{} 文件批量下载RPC调用失败", request_id);

            is_success = false;
            err_msg = "文件批量下载RPC调用失败";

            break;
        }
        if (!rsp.success()) {
            LOG_ERROR("{} 文件批量下载响应错误", request_id);

            is_success = false;
            err_msg = "文件批量下载响应错误";

            break;
        }

        // 5. 将文件数据，存储到info_map中
        auto file_data = rsp.file_data();
        for (auto& user : users) {
            UserInfo info;
            info.set_user_id(user.user_id());

            if (user.phone()) {
                info.set_phone(*user.phone());
            }

            info.set_nickname(user.nickname());

            if (user.description()) {
                info.set_description(*user.description());
            }
            
            if (user.avatar_id()) {
                info.set_avatar(file_data[*user.avatar_id()].file_content());
            }

            (*info_map)[info.user_id()] = info;
        }
    } while (0);

    // 4. 组织响应，返回用户信息
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理批量获取用户数据请求: {}", request_id);
}

void UserServerImpl::SetUserAvatar(
    ::google::protobuf::RpcController* controller,
    const ::chat::SetUserAvatarReq* request, ::chat::SetUserAvatarRsp* response,
    ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";

    LOG_DEBUG("收到设置用户头像请求: {}", request_id);

    do {
        // 1. 从请求中取出用户ID与头像数据
        const std::string user_id = request->user_id();
        const std::string avatar = request->avatar();

        // 2. 从数据库通过用户ID进行用户信息查询，判断用户是否存在
        UserPtr user = odb_user_->select_by_user_id(user_id);
        if (nullptr == user) {
            LOG_ERROR("{}: {}用户不存在", request_id, user_id);

            is_success = false;
            err_msg = "用户不存在";

            break;
        }

        // 3. 上传头像文件到文件子服务
        chat::ServiceChannel::ChannelPtr channel =
            service_manager_->choose(file_service_name_);
        if (nullptr == channel) {
            LOG_ERROR("{}: 未找到能够提供服务 {} 的节点", request_id,
                      file_service_name_);

            is_success = false;
            err_msg = "未找到能够提供服务的节点";

            break;
        }

        // 4. 发起Rpc调用
        chat::FileService_Stub stub(channel.get());
        chat::PutSingleFileReq req;
        chat::PutSingleFileRsp rsp;

        req.set_request_id(Uuid::uuid());
        auto file_data = req.mutable_file_data();
        file_data->set_file_name(Uuid::uuid());
        file_data->set_file_content(avatar);
        file_data->set_file_size(avatar.size());

        brpc::Controller cntl;
        stub.PutSingleFile(&cntl, &req, &rsp, nullptr);
        if (cntl.Failed()) {
            LOG_ERROR("{} 头像文件上传RPC调用失败", request_id);

            is_success = false;
            err_msg = "头像文件上传RPC调用失败";

            break;
        }
        if (!rsp.success()) {
            LOG_ERROR("{} 头像文件上传响应错误", request_id);

            is_success = false;
            err_msg = "头像文件上传响应错误";

            break;
        }

        // 4. 将返回的头像文件ID更新到数据库中
        user->avatar_id(rsp.file_info().file_id());
        if (!odb_user_->update(user)) {
            LOG_ERROR("{}: {} ODB更新头像失败");

            is_success = false;
            err_msg = "ODB更新头像失败";

            break;
        }

        // 5. 更新ES服务器中用户信息
        if (!appendESData(*user)) {
            LOG_ERROR("{}: {} ES更新头像数据失败", request_id, user_id);

            is_success = false;
            err_msg = "ES更新头像数据失败";

            break;
        }
    } while (0);

    // 6. 组织响应，返回更新成功与否
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理设置用户头像请求: {}", request_id);
}

void UserServerImpl::SetUserNickname(
    ::google::protobuf::RpcController* controller,
    const ::chat::SetUserNicknameReq* request,
    ::chat::SetUserNicknameRsp* response, ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";

    LOG_DEBUG("收到设置用户昵称请求: {}", request_id);

    do {
        // 1. 从请求中取出用户ID与新的昵称
        std::string user_id = request->user_id();
        std::string new_nickname = request->nickname();

        // 2. 判断昵称格式是否正确
        if (!checkNickname(new_nickname)) {
            LOG_ERROR("{}: {}昵称长度过长", request_id, new_nickname);

            is_success = false;
            err_msg = "昵称长度过长";

            break;
        }

        // 3. 从数据库通过用户ID进行用户信息查询，判断用户是否存在
        UserPtr user = odb_user_->select_by_user_id(user_id);
        if (nullptr == user) {
            LOG_ERROR("{}: {}用户不存在", request_id, user_id);

            is_success = false;
            err_msg = "用户不存在";

            break;
        }

        // 4. 将新的昵称更新到数据库中
        user->nickname(new_nickname);
        if (!odb_user_->update(user)) {
            LOG_ERROR("{}: {} ODB更新头像失败");

            is_success = false;
            err_msg = "ODB更新头像失败";

            break;
        }

        // 5. 更新ES服务器中用户信息
        if (!appendESData(*user)) {
            LOG_ERROR("{}: {} ES更新头像数据失败", request_id, user_id);

            is_success = false;
            err_msg = "ES更新头像数据失败";

            break;
        }
    } while (0);

    // 6. 组织响应，返回更新成功与否
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理设置用户昵称请求: {}", request_id);
}

void UserServerImpl::SetUserDescription(
    ::google::protobuf::RpcController* controller,
    const ::chat::SetUserDescriptionReq* request,
    ::chat::SetUserDescriptionRsp* response,
    ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";

    LOG_DEBUG("收到设置用户签名请求: {}", request_id);

    do {
        // 1. 从请求中取出用户ID与新的昵称
        std::string user_id = request->user_id();
        std::string new_description = request->description();

        // 2. 从数据库通过用户ID进行用户信息查询，判断用户是否存在
        UserPtr user = odb_user_->select_by_user_id(user_id);
        if (nullptr == user) {
            LOG_ERROR("{}: {}用户不存在", request_id, user_id);

            is_success = false;
            err_msg = "用户不存在";

            break;
        }

        // 3. 将新的昵称更新到数据库中
        user->description(new_description);
        if (!odb_user_->update(user)) {
            LOG_ERROR("{}: {} ODB更新签名失败");

            is_success = false;
            err_msg = "ODB更新签名失败";

            break;
        }

        // 4. 更新ES服务器中用户信息
        if (!appendESData(*user)) {
            LOG_ERROR("{}: {} ES更新签名数据失败", request_id, user_id);

            is_success = false;
            err_msg = "ES更新签名数据失败";

            break;
        }
    } while (0);

    // 5. 组织响应，返回更新成功与否
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理设置用户签名请求: {}", request_id);
}

void UserServerImpl::SetUserPhoneNumber(
    ::google::protobuf::RpcController* controller,
    const ::chat::SetUserPhoneNumberReq* request,
    ::chat::SetUserPhoneNumberRsp* response,
    ::google::protobuf::Closure* done) {
    brpc::ClosureGuard closure_guard(done);

    std::string request_id = request->request_id();
    bool is_success = true;
    std::string err_msg = "OK";

    LOG_DEBUG("收到设置用户手机号请求: {}", request_id);

    do {
        // 1. 从请求中取出手机号码和验证码ID，以及验证码。
        std::string phone = request->phone_number();
        std::string code = request->phone_verify_code();
        std::string code_id = request->phone_verify_code_id();

        // 2. 检查注册手机号码是否合法
        if (!checkPhone(phone)) {
            LOG_ERROR("{}: {} 手机号格式错误", request_id, phone);

            is_success = false;
            err_msg = "手机号格式错误";

            break;
        }

        // 3. 从redis数据库中进行验证码ID-验证码一致性匹配
        auto res = redis_codes_->code(code_id);
        if (res != code) {
            LOG_ERROR("{}: {} 验证码错误", code);

            is_success = false;
            err_msg = "验证码错误";

            break;
        }
        redis_codes_->remove(code_id);  // 使用完验证码后，就要从redis中删除

        // 4. 根据uid从数据数据进行用户信息查询，判断用用户是否存在
        UserPtr user = odb_user_->select_by_user_id(request->user_id());
        if (user == nullptr) {
            LOG_ERROR("{}: {} 手机号还未注册", phone);

            is_success = false;
            err_msg = "手机号还未注册";

            break;
        }

        // 5. 将新的手机号更新到数据库中
        user->phone(phone);
        if (!odb_user_->update(user)) {
            LOG_ERROR("{}: {} ODB更新手机号失败");

            is_success = false;
            err_msg = "ODB更新手机号失败";

            break;
        }

        // 6. 更新ES服务器中用户信息
        if (!appendESData(*user)) {
            LOG_ERROR("{}: {} ES更新手机号失败", request_id, user->user_id());

            is_success = false;
            err_msg = "ES更新手机号失败";

            break;
        }

    } while (0);

    // 7. 组织响应，返回更新成功与否
    response->set_request_id(request_id);
    response->set_success(is_success);
    response->set_errmsg(err_msg);

    LOG_DEBUG("成功处理设置用户手机号请求: {}", request_id);
}

// -------------------------------------------------------------------

// UserServerBuilder

void UserServerBuilder::makeRegisterClient(const std::string& register_name,
                                           const std::string& etcd_host,
                                           const std::string& access_host) {
    register_client_ = std::make_shared<Registry>(etcd_host);

    register_client_->registry(register_name, access_host);
}

void UserServerBuilder::makeServiceManager(
    const std::string& file_service_name) {
    service_manager_ = std::make_shared<ServiceManager>();
    service_manager_->declared(file_service_name);  // 添加关心

    file_service_name_ = file_service_name;
}

void UserServerBuilder::makeDiscoveryClient(const std::string& etcd_host,
                                            const std::string& base_service) {
    discovery_client_ = std::make_shared<Discovery>(
        etcd_host, base_service,
        std::bind(&ServiceManager::onServiceOnline, service_manager_.get(),
                  std::placeholders::_1, std::placeholders::_2),
        std::bind(&ServiceManager::onServiceOffline, service_manager_.get(),
                  std::placeholders::_1, std::placeholders::_2));
}

void UserServerBuilder::makeBrpcServer(const uint16_t port,
                                       const int idle_timeout_sec,
                                       const int num_threads) {
    // 检查
    if (es_client_ == nullptr) {
        LOG_ERROR("ES 客户端未初始化");
        abort();
    }
    if (redis_client_ == nullptr) {
        LOG_ERROR("Redis 客户端未初始化");
        abort();
    }
    if (odb_client_ == nullptr) {
        LOG_ERROR("ODB 客户端未初始化");
        abort();
    }
    if (sms_client_ == nullptr) {
        LOG_ERROR("SMS 客户端未初始化");
        abort();
    }
    if (service_manager_ == nullptr) {
        LOG_ERROR("服务管理对象 未初始化");
        abort();
    }

    brpc_server_ = std::make_shared<brpc::Server>();
    UserServerImpl* user_service =
        new UserServerImpl(es_client_, redis_client_, odb_client_, sms_client_,
                           service_manager_, file_service_name_);
    if (-1 == brpc_server_->AddService(
                  user_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE)) {
        LOG_ERROR("RPC添加服务失败");
        abort();
    }

    brpc::ServerOptions options;
    options.idle_timeout_sec = idle_timeout_sec;
    options.num_threads = num_threads;

    if (-1 == brpc_server_->Start(port, &options)) {
        LOG_ERROR("RPC服务启动失败");
        abort();
    }
}

void UserServerBuilder::makeOdbClient(
    const int max_pool, const std::string& user, const std::string& password,
    const std::string& db, const std::string& ip, const uint16_t port,
    const std::string& charset) {
    odb_client_ = DataBaseFactory::create(max_pool, user, password, db, ip,
                                          port, charset);
}

void UserServerBuilder::makeRedisClient(const std::string& ip,
                                        const uint16_t port, const int db,
                                        const bool keep_alive) {
    redis_client_ = RedisClientFactory::create(ip, port, db, keep_alive);
}

void UserServerBuilder::makeEsClient(const std::vector<std::string> host_list) {
    es_client_ = ESClientFactory::create(host_list);
}

void UserServerBuilder::makeSMSClient(const std::string& api_key) {
    sms_client_ = std::make_shared<SpugSMSCodeSender>(api_key);
}

UserServerPtr UserServerBuilder::build() {
    if (register_client_ == nullptr) {
        LOG_FATAL("服务注册客户端未实例化");
        abort();
    }
    if (discovery_client_ == nullptr) {
        LOG_FATAL("服务发现客户端未实例化");
        abort();
    }
    if (brpc_server_ == nullptr) {
        LOG_FATAL("RPC服务未实例化");
        abort();
    }

    return std::make_shared<UserServer>(register_client_, discovery_client_,
                                        brpc_server_, es_client_, redis_client_,
                                        odb_client_);
}
}  // namespace chat